// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#pragma once
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include "fastflow/core/visibility_macros.h"

#ifdef __cplusplus
//Windows user should use unicode path whenever possible, to bypass the MAX_PATH limitation
//Evevy type name started with 'P' is a pointer type, an opaque handler
//Every pointer marked with _In_ or _Out_, cannot be NULL. Caller should ensure that.
//for ReleaseXXX(...) functions, they can accept NULL pointer.
#define NO_EXCEPTION noexcept
#else
#define NO_EXCEPTION
#endif

#ifdef __cplusplus
extern "C" {
#endif
typedef enum FASTFLOWErrorCode {
  FASTFLOW_OK = 0,
  FASTFLOW_FAIL = 1,
  FASTFLOW_INVALID_ARGUMENT = 2,
  FASTFLOW_NO_SUCHFILE = 3,
  FASTFLOW_NO_MODEL = 4,
  FASTFLOW_ENGINE_ERROR = 5,
  FASTFLOW_RUNTIME_EXCEPTION = 6,
  FASTFLOW_INVALID_PROTOBUF = 7,
  FASTFLOW_MODEL_LOADED = 8,
  FASTFLOW_NOT_IMPLEMENTED = 9,
  FASTFLOW_INVALID_GRAPH = 10,
  FASTFLOW_SHAPE_INFERENCE_NOT_REGISTERED = 11,
  FASTFLOW_REQUIREMENT_NOT_REGISTERED = 12
} FASTFLOWErrorCode;

//nullptr indicates success. Otherwise, this pointer must be freed by
typedef void* ONNXStatusPtr;

#ifdef _WIN32
#define FASTFLOW_API_STATUSCALL _stdcall
#else
#define FASTFLOW_API_STATUSCALL
#endif

//__VA_ARGS__ on Windows and Linux are different
#define FASTFLOW_API(RETURN_TYPE, NAME, ...) \
  FASTFLOW_EXPORT RETURN_TYPE FASTFLOW_API_STATUSCALL NAME(__VA_ARGS__) NO_EXCEPTION

#define FASTFLOW_API_STATUS(NAME, ...) \
  FASTFLOW_EXPORT ONNXStatusPtr FASTFLOW_API_STATUSCALL NAME(__VA_ARGS__) NO_EXCEPTION FASTFLOW_MUST_USE_RESULT

//Used in *.cc files. Almost as same as FASTFLOW_API_STATUS, expect without FASTFLOW_MUST_USE_RESULT
#define FASTFLOW_API_STATUS_IMPL(NAME, ...) \
  FASTFLOW_EXPORT ONNXStatusPtr FASTFLOW_API_STATUSCALL NAME(__VA_ARGS__) NO_EXCEPTION

#define DEFINE_RUNTIME_CLASS2(NAME, TYPE) \
  typedef TYPE* NAME##Ptr;                \
  FASTFLOW_API(void, Release##NAME, _Frees_ptr_opt_ TYPE* input);

#define DEFINE_RUNTIME_CLASS(X) \
  struct X;                     \
  typedef struct X X;           \
  DEFINE_RUNTIME_CLASS2(X, X)

//ONNXStatusPtr is pointer to something like this:
//struct ONNXStatus{
//  FASTFLOWErrorCode code;
//  char msg[];//a null-terminated string, var length
//}
DEFINE_RUNTIME_CLASS2(ONNXStatus, void);

/**
 * \param msg A null-terminated string. Its content will be copied into the newly created ONNXStatus
 */
FASTFLOW_API(ONNXStatusPtr, CreateONNXStatus, FASTFLOWErrorCode code, _In_ const char* msg)
FASTFLOW_ALL_ARGS_NONNULL;

FASTFLOW_API(FASTFLOWErrorCode, FASTFLOWGetErrorCode, _In_ const ONNXStatusPtr status)
FASTFLOW_ALL_ARGS_NONNULL;
/**
 * \param status must not be NULL
 * \return The error message inside the `status`. Don't free the returned value.
 */
FASTFLOW_API(const char*, FASTFLOWGetErrorMessage, _In_ const ONNXStatusPtr status)
FASTFLOW_ALL_ARGS_NONNULL;
#ifdef __cplusplus
}
#endif
